package ipx

import (
	"context"
	"fmt"
)

/*
直接返回 IP 的服务:
"https://ipv4.icanhazip.com"
"https://checkip.amazonaws.com"
"https://ifconfig.me/ip"
"https://ipinfo.io/ip"
"https://ipecho.net/ip"
"https://eth0.me"
"https://l2.io/ip"
"https://ipaddress.sh"
"https://wgetip.com"
"https://ipaddr.site"
"https://ip.tyk.nu"
"https://ipcalf.com"
"https://ifconfig.es"
"https://ident.me"
"https://curlmyip.net"

返回 JSON 的服务:
"https://ipinfo.io/what-is-my-ip" - 返回格式:
{
  "ip":"154.18.180.43",
  "city":"Singapore",
  "region":"Singapore",
  "country":"SG",
  "loc":"1.2897,103.8501",
  "org":"AS136897 Enjoyvc Cloud Group Limited.",
  "postal":"018989",
  "timezone":"Asia/Singapore",
  "readme":"https://ipinfo.io/missingauth"
}
*/

var (
	// 所有可用的 IP 获取器
	_IpGetters = []IpGetter{
		NewHTTPIpGetter("https://ipv4.icanhazip.com"),
		NewHTTPIpGetter("https://checkip.amazonaws.com"),
		NewHTTPIpGetter("https://ifconfig.me/ip"),
		NewHTTPIpGetter("https://ipinfo.io/ip"),
		NewHTTPIpGetter("https://ipecho.net/ip"),
		NewHTTPIpGetter("https://eth0.me"),
		NewHTTPIpGetter("https://l2.io/ip"),
		NewHTTPIpGetter("https://ipaddress.sh"),
		NewHTTPIpGetter("https://wgetip.com"),
		NewHTTPIpGetter("https://ipaddr.site"),
		NewHTTPIpGetter("https://ip.tyk.nu"),
		NewHTTPIpGetter("https://ipcalf.com"),
		NewHTTPIpGetter("https://ifconfig.es"),
		NewHTTPIpGetter("https://ident.me"),
		NewHTTPIpGetter("https://curlmyip.net"),
		NewJSONIpGetter("https://ipinfo.io/what-is-my-ip", "ip"),
	}

	// 默认配置参数
	_DefaultIpGetterConfig = IpGetterConfig{
		// 默认只需要1个服务返回结果
		MinConsensusCount: 1,
		// 默认并发数量
		Concurrency: 1,
	}
)

// IpGetterConfig 获取IP的配置参数
type IpGetterConfig struct {
	// 获取结果中最低相同IP数量（共识数量）
	// 当至少有这么多服务返回相同IP时，认为该IP可信
	MinConsensusCount int
	// 并发数量
	Concurrency int
	// Getters洗牌概率：0-1之间，0表示不洗牌，1表示每次都洗牌
	ShuffleGetterProbability float64
}

// IpGetter 接口定义了获取 IP 的方法
type IpGetter interface {
	GetMyIP(ctx context.Context) (string, error)
}

// FallbackIpGetter 尝试多个 IP 获取器，直到成功
type FallbackIpGetter struct {
	Getters []IpGetter
}

// NewFallbackIpGetter 使用所有可用的获取器创建一个回退 IP 获取器
func NewFallbackIpGetter() *FallbackIpGetter {
	return &FallbackIpGetter{
		Getters: _IpGetters,
	}
}

// GetMyIP 尝试使用所有配置的获取器获取 IP，直到成功
func (g *FallbackIpGetter) GetMyIP(ctx context.Context) (string, error) {
	var lastErr error
	for _, getter := range g.Getters {
		ip, err := getter.GetMyIP(ctx)
		if err == nil && ip != "" {
			return ip, nil
		}
		lastErr = err
	}
	return "", fmt.Errorf("all IP getters failed, last error: %w", lastErr)
}

// GetMyIP 是便捷函数，使用默认配置获取 IP
func GetMyIP() (string, error) {
	// 使用默认配置
	return GetMyIPWithConfig(_DefaultIpGetterConfig)
}

// GetMyIPReliable 使用指定的共识数量获取IP
// consensusCount 表示至少需要多少个服务返回相同结果才认为可信
// concurrency 表示并发数量
func GetMyIPReliable(consensusCount, concurrency int) (string, error) {
	config := IpGetterConfig{
		MinConsensusCount: consensusCount,
		Concurrency:       concurrency,
	}
	return GetMyIPWithConfig(config)
}

// GetMyIPWithConfig 使用自定义配置获取IP
func GetMyIPWithConfig(config IpGetterConfig) (string, error) {
	if config.MinConsensusCount <= 0 {
		return "", fmt.Errorf("MinConsensusCount must be greater than 0")
	}

	// 使用组合获取器
	combined, err := NewCombinedIpGetter(_IpGetters, config)
	if err != nil {
		return "", err
	}
	return combined.GetMyIP(context.Background())
}
